import os
import sys
import asyncio
import websockets.server
import websockets.exceptions as wexc
import threading
import logging
import traceback


logger = logging.getLogger(__name__)


class Server:
    def __init__(self, master, host, port):
        '''
        Argv:
            master
                - .new_link(link, tag)
                - .process(link, tag, msg)
                - .link_closed(tag, closed)
        '''
        self.m = master
        self.host = host
        self.port = port
        return


    async def ws_handler(self, websocket, path):
        tag = websocket.id

        if not await self.m.new_link(websocket, tag):
            return

        try:
            async for message in websocket:
                resp = await self.m.process(websocket, tag, message)
                #if resp is 'quit', then quit
                if resp == 'quit':
                    #await asyncio.sleep(.01)
                    break
        except (wexc.ConnectionClosedError, wexc.ConnectionClosedOK):
            logger.info(f'[Except] {sys.exc_info()[1]}')
        except:
            logger.error(traceback.format_exc())
            if self.m.DEBUG: os._exit(1)

        self.m.link_closed(tag, websocket.closed)


    async def main(self):
        async with websockets.server.serve(self.ws_handler, self.host, self.port):
            await asyncio.Future()


    def run(self):
        asyncio.run(self.main())


    def __call__(self):
        threading.Thread(
            target = self.run,
            daemon = True,
            name = 'server'
        ).start()
        return self


